from io import BytesIO
import docker
from .Helper import *


class DockerManager:
    def __init__(self) -> None:
        self.base_url = None
        self.sign = "api"
        self.api_version = ""
        self.success_code = 0
        self.fail_code = 1

    def __client(self):
        if self.base_url is not None:
            docker_client = docker.DockerClient(base_url=self.base_url)
        else:
            docker_client = None
        return docker_client

    def __search_image(self, tag):
        try:
            client = self.__client()
            res = client.images.search(tag)
            client.close()
            return {"error_num": self.success_code, "msg": "查询成功", "data": res}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "查询失败： %s" % str(e), "data": []}

            # 镜像历史

    def __history_image(self, tag):
        try:
            client = self.__client()
            res = client.api.history(tag)
            client.close()
            return {"error_num": self.success_code, "msg": "查询成功", "data": res}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "查询失败： %s" % str(e), "data": []}

            # 提交镜像

    def __push_image(self, repository):
        try:
            client = self.__client()
            res = client.api.push(repository=repository)
            client.close()
            return {"error_num": self.success_code, "msg": "提交成功", "data": res}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "提交失败： %s" % str(e), "data": []}

            # 重命名镜像

    def __tag_image(self, image, repository):
        try:
            client = self.__client()
            res = client.api.tag(image=image, repository=repository)
            client.close()
            return {"error_num": self.success_code, "msg": "提交成功", "data": res}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "提交失败： %s" % str(e), "data": []}

            # 扩展提交镜像

    def __ext_push(self, image, repository):
        try:
            client = self.__client()
            res = client.api.tag(image=image, repository=repository)
            if res:
                pres = client.api.push(repository=repository)
                client.close()
                return {"error_num": self.success_code, "msg": "提交成功", "data": pres}
            else:
                return {"error_num": self.fail_code, "msg": "提交失败： %s" % str(res), "data": []}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "提交失败： %s" % str(e), "data": []}

            # 重命名容器

    def __rename_containers(self, oldname, newname):
        try:
            client = self.__client()
            client.api.rename(oldname, newname)
            client.close()
            return {"error_num": self.success_code, "msg": "重命名成功", "data": []}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "重命名失败： %s" % str(e), "data": []}

            # 重启容器

    def change_docker_url(self, request):
        if request.method == "POST":
            url = request.POST.get("url", None)
            if not url:
                return 1, "error", self.base_url
            else:
                self.base_url = "tcp://{}:8088".format(url)
                return 1, "success", self.base_url

    def containers(self):
        try:
            client = self.__client()
            container_list = client.api.containers(all=True)
            client.close()
            containers = []
            if container_list:
                for container in container_list:
                    id = container["Id"]
                    names = container["Names"][0].split("/")[1]
                    image = container["Image"]
                    if container["Ports"]:
                        ports = []
                        for ptp in container["Ports"]:
                            if "PublicPort" in ptp.keys():
                                pstr = ptp["IP"] + ":" + str(ptp["PublicPort"]) + "->" + str(ptp["PrivatePort"])
                                ports.append(pstr)
                    else:
                        ports = container["Ports"]
                    status = container["State"]

                    if container["Mounts"]:
                        mount = []
                        for mtp in container["Mounts"]:
                            if mtp["Source"]:
                                mtp_str = mtp["Source"] + ":" + mtp["Destination"]
                                mount.append(mtp_str)
                    else:
                        mount = container["Mounts"]
                    container_dict = {"id": id, "name": names, "image": image, "ports": ports, "status": status,
                                      "mount": mount}
                    containers.append(container_dict)
            return {"error_num": self.success_code, "msg": "获取成功", "data": containers}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "获取失败 %s" % str(e), "data": []}

            # 返回本地镜像列表: 镜像tag 镜像大小 镜像创建时间

    def images(self):
        try:
            client = self.__client()
            images = client.api.images(all=True)
            client.close()
            images_res = []
            for image in images:
                id = image["Id"].split(":")[1]
                repo = image["RepoTags"][0].split(":")[0]
                tag = image["RepoTags"][0].split(":")[1]
                size = round(image["Size"] / 1024.0 / 1024.0, 3)
                created = image["Created"]
                images_res.append(
                    {"id": id, "repo": repo, "tag": tag, "size": size, "created": utc_int_to_date(created)})
            return {"error_num": self.success_code, "msg": "获取成功", "data": images_res}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "获取失败 %s" % str(e), "data": []}

            # 拉取镜像

    def pull_image(self, tag):
        try:
            client = self.__client()
            client.images.pull(repository=tag)
            images = client.api.images(all=True)
            client.close()
            images_res = []
            for image in images:
                id = image["Id"].split(":")[1]
                repo = image["RepoTags"][0].split(":")[0]
                tag = image["RepoTags"][0].split(":")[1]
                size = round(image["Size"] / 1024.0 / 1024.0, 3)
                created = image["Created"]
                images_res.append(
                    {"id": id, "repo": repo, "tag": tag, "size": size, "created": utc_int_to_date(created)})
            return {"error_num": self.success_code, "msg": "拉取成功", "data": images_res}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "拉取失败： ", "data": [e]}

            # 删除镜像

    def del_image(self, tag):
        try:
            client = self.__client()
            client.images.remove(image=tag)
            images = client.api.images(all=True)
            client.close()
            images_res = []
            for image in images:
                id = image["Id"].split(":")[1]
                repo = image["RepoTags"][0].split(":")[0]
                tag = image["RepoTags"][0].split(":")[1]
                size = round(image["Size"] / 1024.0 / 1024.0, 3)
                created = image["Created"]
                images_res.append(
                    {"id": id, "repo": repo, "tag": tag, "size": size, "created": utc_int_to_date(created)})
            return {"error_num": self.success_code, "msg": "删除成功", "data": images_res}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "删除失败： %s" % str(e), "data": []}

            # 镜像搜索

    def restart_containers(self, id):
        try:
            client = self.__client()
            client.api.restart(id)
            client.close()
            return {"error_num": self.success_code, "msg": "重启成功", "data": []}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "重启失败： %s" % str(e), "data": []}

            # 启动容器

    def start_containers(self, id):
        try:
            client = self.__client()
            client.api.start(id)
            client.close()
            return {"error_num": self.success_code, "msg": "启动成功", "data": []}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "启动失败： %s" % str(e), "data": []}

            # 停止容器

    def stop_containers(self, id):
        try:
            client = self.__client()
            client.api.stop(id)
            client.close()

            return {"error_num": self.success_code, "msg": "停止成功", "data": []}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "停止失败： %s" % str(e), "data": []}

            # 删除容器

    def del_containers(self, id):
        try:
            stopRes = self.stop_containers(id)
            if stopRes["error_num"] == 0:
                client = self.__client()
                client.api.remove_container(id)
                client.close()
                return {"error_num": self.success_code, "msg": "删除成功", "data": []}
            else:
                return {"error_num": self.fail_code, "msg": "删除失败： %s" % stopRes['msg'], "data": []}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "删除失败： %s" % str(e), "data": []}

            # 创建容器

    def run_containers(self, data):
        try:
            client = self.__client()
            if ";" in data["binds"]:
                volumes = data["binds"].split(";")
            elif ":" in [data["binds"]]:
                volumes = [data["binds"]]
            else:
                volumes = []
            prots = {}
            if ";" in data["port_bindings"]:
                portLst = data["port_bindings"].split(";")
                prots = {}
                for port in portLst:
                    key = port.split(":")[1]
                    value = port.split(":")[0]
                    prots[key] = value
            elif data["port_bindings"]:
                key = data["port_bindings"].split(":")[1]
                value = data["port_bindings"].split(":")[0]
                prots[key] = value
            if data["nano_cpus"]:
                nano_cpus = int(data["nano_cpus"]) * 1000000000
            else:
                nano_cpus = ""

            if ";" in data["environment"]:
                environment = data["environment"].split(";")
            elif ":" in data["environment"]:
                environment = [data["environment"]]
            else:
                environment = []

            container = client.containers.create(
                image=data["image"],
                environment=environment,
                hostname=data["hostname"],
                name=data["name"],
                nano_cpus=nano_cpus,
                mem_limit=data["mem_limit"],
                network=data["network"],
                volumes=volumes,
                ports=prots,
                detach=True,
                network_mode=data["network_mode"],
                restart_policy=data["restart_policy"],
                shm_size=data["shmsize"]
            )
            container.start()
            client.close()
            return {"error_num": self.success_code, "msg": "创建成功： %s" % container.id, "data": []}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "创建失败： %s" % str(e), "data": []}

            # 构建镜像

    def build(self, dockerfile, tag):
        try:
            client = self.__client()
            f = BytesIO(dockerfile.encode('utf-8'))
            response = [line for line in client.api.build(fileobj=f, rm=True, tag=tag, nocache=True)]
            res_data = eval(response[-1])
            client.close()
            if "Successfully tagged" in str(res_data):
                return {"error_num": self.success_code, "msg": "build成功", "data": [res_data]}
            else:
                return {"error_num": self.fail_code, "msg": "build失败", "data": [res_data]}
        except Exception as e:
            return {"error_num": self.fail_code, "msg": "build失败： %s" % str(e), "data": []}
